package de.swta.freezay.admin.itemPackage;

import de.swta.freezay.admin.category.CategoryEditPanel;
import de.swta.freezay.admin.item.InDecreasePanel;
import de.swta.freezay.components.CategoryChoiceRenderer;
import de.swta.freezay.database.JPAController;
import de.swta.freezay.database.controller.exceptions.IllegalOrphanException;
import de.swta.freezay.database.controller.exceptions.NonexistentEntityException;
import de.swta.freezay.database.controller.exceptions.PreexistingEntityException;
import de.swta.freezay.database.dbEntities.Category;
import de.swta.freezay.database.dbEntities.Item;
import de.swta.freezay.database.dbEntities.ItemPackage;
import de.swta.freezay.database.dbEntities.Package;
import java.text.DecimalFormat;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.Locale;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.text.NumberFormatter;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.markup.html.AjaxLink;
import org.apache.wicket.ajax.markup.html.form.AjaxSubmitLink;
import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow;
import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.form.DropDownChoice;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.RequiredTextField;
import org.apache.wicket.markup.html.form.TextArea;
import org.apache.wicket.markup.html.list.ListItem;
import org.apache.wicket.markup.html.list.ListView;
import org.apache.wicket.markup.html.panel.FeedbackPanel;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.model.CompoundPropertyModel;
import org.apache.wicket.model.PropertyModel;
import org.apache.wicket.validation.validator.DateValidator;
import org.apache.wicket.validation.validator.RangeValidator;
import org.apache.wicket.validation.validator.StringValidator.LengthBetweenValidator;

public abstract class PackageEditPanel extends Panel {

    /** Formatter for numbers. */
    private static final NumberFormatter NUMBER_FORMATTER =
            new NumberFormatter(new DecimalFormat("####.##"));
    /** Item list. */
    ListView itemList;
    /** Input form for editing a package. */
    Form packageForm;
    /** EditMode is true if an package is edited, otherwise false. */
    boolean editMode = false;
    /** Modal window for edit the items of the package. */
    final ModalWindow modalWindow = new ModalWindow("modalWindow");
    /** MarkupContainer with the listview for update. */
    WebMarkupContainer theContainer = new WebMarkupContainer("theContainer");
    /** Panel to add items to the package. */
    AddItemsToPackagePanel itemsPanel;
    /** Package to edit or create. */
    protected Package packageToEdit;

    /**
     * Creates a new instance of PackageEditPanel.
     *
     * @param id Id of the Panel.
     * @param packageId Id of the package tp edit or create.
     * @param editMode is true if an package is edited, otherwise false.
     */
    public PackageEditPanel(String id, int packageId, boolean editMode) {
        super(id);

        this.editMode = editMode;
        init(packageId);
    }

    /**
     * Initializes the panel with it's all components.
     *
     * @param packageId Id of the package to display.
     */
    private void init(int packageId) {

        if (editMode) {
            /* if editMode get the package. */
            packageToEdit = JPAController.PackageJpaController.findPackage(packageId);
        } else {
            /** Otherwise it's created. */
            packageToEdit = new Package();
            try {
                JPAController.PackageJpaController.create(packageToEdit);
            } catch (PreexistingEntityException ex) {
                Logger.getLogger(PackageEditPanel.class.getName()).log(Level.SEVERE, null, ex);
            } catch (Exception ex) {
                Logger.getLogger(PackageEditPanel.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        final boolean isReserved = packageToEdit.isReserved();

        /** Create the formular for package editing. */
        this.packageForm = new Form("packageForm");
        this.packageForm.add(new RequiredTextField("name").add(
                                    new LengthBetweenValidator(3, 20)));
        this.packageForm.add(new TextArea("description"));

        /* Choices of all categories. */
        List<Category> catList = JPAController.CategoryJpaController.findCategoryEntities();
        final PropertyModel<Category> categoryChoicePropertyModel = 
                        new PropertyModel<Category>(packageToEdit, "category");

        DropDownChoice<Category> categoryChoice = new DropDownChoice<Category>(
                "category",
                categoryChoicePropertyModel,
                catList,
                new CategoryChoiceRenderer());

        /* Set first category as selected. */
        categoryChoice.setNullValid(false);
        categoryChoice.setRequired(true);
        categoryChoice.setModelObject(catList.get(0));
        this.packageForm.add(categoryChoice);
        this.packageForm.add(new RequiredTextField("discount").add(new RangeValidator(0d, 90d)));

        /* Mininimum date for validation. */
        Date minDate = new Date(System.currentTimeMillis());
        Locale.setDefault(Locale.GERMANY);
        this.packageForm.add(new RequiredTextField("validity").add(
                                        DateValidator.minimum(minDate)));

        this.packageForm.add(new AjaxSubmitLink("saveLink") {

            @Override
            protected void onSubmit(AjaxRequestTarget target, Form<?> form) {
                Package p = (Package) packageForm.getModelObject();

                if (editMode) {
                    /* If edited - the package is stored to DB. */
                    try {
                       
                        List<ItemPackage> itemPackages = p.getItemPackageCollection();
                        List<ItemPackage> removeList = new ArrayList<ItemPackage>();
                        for (ItemPackage editedItem : itemPackages) {
                            /* Iterate over all ItemPackages. */
                            if (editedItem.getItemCount() == 0) {
                                /* if the count is zero, the ItemPackage is destroyed. */
                                JPAController.ItemPackageJpaController.destroy(
                                                editedItem.getItemPackagePK());
                                removeList.add(editedItem);
                            } else {
                                if (JPAController.ItemPackageJpaController.
                                            findItemPackage(editedItem.getItemPackagePK()) == null) {
                                    /* ItemPackage doesn't exists in DB - Create it. */
                                    JPAController.ItemPackageJpaController.create(editedItem);
                                } else {
                                    /* Otherwise edit the IptamPackage with
                                     * different itemCount. */
                                    JPAController.ItemPackageJpaController.edit(editedItem);
                                }
                            }
                        }

                        /* All itemPackages with itemCount zero - remove them
                         * from the Package-Entity. */
                        for(ItemPackage remPackage : removeList) {
                            itemPackages.remove(remPackage);
                        }

                        /* calculate the new price with disount. */
                        p.setPrice(p.calculatePrice());
                        /* Save the package to DB. */
                        JPAController.PackageJpaController.edit(p);

                    } catch (NonexistentEntityException ex) {
                        Logger.getLogger(CategoryEditPanel.class.getName()).log(Level.SEVERE, null, ex);
                    } catch (Exception ex) {
                        Logger.getLogger(CategoryEditPanel.class.getName()).log(Level.SEVERE, null, ex);
                    }
                } else {
                    /* Save New package. */
                    try {
                        List<ItemPackage> itemPackages = p.getItemPackageCollection();

                        for (ItemPackage editedItem : itemPackages) {
                            JPAController.ItemPackageJpaController.create(editedItem);
                        }
                        /* calculate the new price with disount. */
                        p.setPrice(p.calculatePrice());
                        /* Save the package to DB. */
                        JPAController.PackageJpaController.edit(p);

                    } catch (NonexistentEntityException ex) {
                        Logger.getLogger(CategoryEditPanel.class.getName()).log(
                                                Level.SEVERE, null, ex);
                    } catch (Exception ex) {
                        Logger.getLogger(CategoryEditPanel.class.getName()).log(
                                                Level.SEVERE, null, ex);
                    }
                }
                PackageEditPanel.this.saveLink(target);
            }

            /**
             * Handles error messages of the form.
             */
            @Override
            protected void onError(AjaxRequestTarget target, Form<?> form) {
                target.addComponent(this.getParent().get("feedback"));
                super.onError(target, form);
            }
        });

        add(new Label("textLabel", ""));

        this.theContainer = new WebMarkupContainer("theContainer");
        this.packageForm.setModel(new CompoundPropertyModel(packageToEdit));
        this.packageForm.add(new FeedbackPanel("feedback").setOutputMarkupId(true));
        add(this.packageForm);

        /* Add/ remove items to package. */
        add(new AjaxLink("addItem") {

            @Override
            public void onClick(AjaxRequestTarget target) {
                target.appendJavascript("Wicket.Window.unloadConfirmation = false;");

                modalWindow.setContent(new AddItemsToPackagePanel(modalWindow.getContentId(),
                                    packageToEdit, PackageEditPanel.this.editMode) {

                    @Override
                    public void onConfirm(AjaxRequestTarget target) {
                        modalWindow.close(target);
                        /* Add/ remove items to package. */
                        savePackageContent();
                        target.addComponent(PackageEditPanel.this.theContainer);
                    }
                });
                modalWindow.setInitialHeight(500);
                modalWindow.setInitialWidth(650);
                modalWindow.setTitle("Produkte hinzufügen/ entfernen");
                modalWindow.show(target);
            }
        });

        /* Item List. */
        this.itemList = new ListView("itemList", packageToEdit.getItemPackageCollection()) {

            protected void populateItem(ListItem item) {

                /* Display one item in the itemList. */
                final ItemPackage ip = (ItemPackage) item.getModelObject();
                final Item i = (ip).getItem();

                item.add(new Label("name", i.getName()));
                item.add(new Label("category", i.getCategory().getName()));
                try {
                    item.add(new Label("amount", "" +
                            NUMBER_FORMATTER.valueToString(i.getAmount())));
                    item.add(new Label("price", "" +
                            NUMBER_FORMATTER.valueToString(i.getPrice()) +
                            " €"));

                } catch (ParseException ex) {
                    Logger.getLogger(PackageEditPanel.class.getName()).log(
                                                Level.SEVERE, null, ex);
                }
                item.add(new Label("unit", "" + i.getUnit().getName()));
                item.add(new Label("count", "" + ((ItemPackage) item.getModelObject()).getItemCount()));
                item.add(new InDecreasePanel("indecrease") {

                    @Override
                    public void onIncrease(AjaxRequestTarget target) {
                        int packageCount = packageToEdit.getCount().intValue();
                        
                        if (((ip.getItemCount() + 1) * packageCount) 
                                                <= i.getRemainingCount()) {
                            /* Increase if items enough items are availeable.  */
                            ip.setItemCount(ip.getItemCount() + 1);
                            target.addComponent(theContainer);
                        }
                    }

                    @Override
                    public void onDecrease(AjaxRequestTarget target) {
                        if (!isReserved) {
                            /* Decrease itemCount if the package is not reserved. */
                            ip.setItemCount(ip.getItemCount() - 1);
                            target.addComponent(theContainer);
                        }
                    }
                });
            }
        };

        this.theContainer.setOutputMarkupId(true);
        this.itemList.setOutputMarkupId(true);
        this.theContainer.add(itemList);
        add(this.theContainer);
        add(modalWindow);
    }

    /**
     * Sets a message to the messageLabel.
     *
     * @param text Text to display
     */
    public void setMessageText(String text) {
        this.remove("textLabel");
        add(new Label("textLabel", text));
    }

    /**
     * Discards a package, if the package has not to save to DB.
     */
    public void discardActPackage() {
        try {
            JPAController.PackageJpaController.destroy(this.packageToEdit.getId());
        } catch (IllegalOrphanException ex) {
            Logger.getLogger(PackageEditPanel.class.getName()).log(Level.SEVERE, null, ex);
        } catch (NonexistentEntityException ex) {
            Logger.getLogger(PackageEditPanel.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    /**
     * Handles the actions after submitLink was clicked.
     *
     * @param target AjaxRequestTarget
     */
    public abstract void saveLink(AjaxRequestTarget target);
}

